#! /bin/env python
import argparse
import logging
import os


class AXI_CFG_TRACER(object):

    def __init__(self):
        self.SetArgsLogger()
        self.axi_signal_d = {
            "awready"   :   None,
            "awvalid"   :   None,
            "arready"   :   None,
            "arvalid"   :   None,
            "wready"    :   None,
            "wvalid"    :   None,
            "rready"    :   None,
            "rvalid"    :   None,
            "bready"    :   None,
            "bvalid"    :   None,
            "bresp"     :   None,
            "awaddr"    :   None,
            "araddr"    :   None,
            "wdata"     :   None,
            "rresp"     :   None,
            "rdata"     :   None
                            }

    def SetArgsLogger(self):
       parser = argparse.ArgumentParser(description='3D GPU CMD2CTest FLow self.args Parser')
       parser.add_argument('--fsdb', action="store", dest="fsdb", default=None,\
                         help="input the fsdb files")
       parser.add_argument('--cfg', action='store', dest="cfg", default=None,\
                         help="set the cfg")
       parser.add_argument('-o', '--output', action='store', dest="outfile", default="axi.trace", \
                         help="set the output file name")
       parser.add_argument('-d', '--debug', action='store_true', dest="debug", default=False, \
                         help="enable debug mode")
       self.args=parser.parse_args()
    
       self.logger = logging.getLogger(__name__)
    
       if self.args.debug: 
         log_mode = logging.DEBUG
       else:
         log_mode = logging.INFO
       self.logger.setLevel(level = log_mode)
       
       handler = logging.FileHandler("tracer.log.")
       handler.setLevel(log_mode)
       formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
       handler.setFormatter(formatter)
        
       console = logging.StreamHandler()
       console.setLevel(log_mode)
        
       self.logger.addHandler(handler)
       self.logger.addHandler(console)
       
       if self.args.debug:
           logging.debug(self.args)

    def GetSignalPath(self):
        assert self.args.cfg != None, "No cfg file set!!!"
        cfg_path = self.args.cfg
        assert os.path.isfile(cfg_path), "No cfg file under existed!!!"

        with open(cfg_path) as fh:
            lines = fh.readlines()
            for line in lines:
                signals = line.split(" ") 
                assert signals[0] in  self.axi_signal_d.keys(), "invalid signal : %s "%(signals[0])
                self.axi_signal_d[signals[0]] = signals[1].strip()
            
        for i in self.axi_signal_d.keys():
            assert self.axi_signal_d[i] != None, "%s path not set"%i
    
    def GetSignalTempFile(self):
        assert os.path.isfile(self.args.fsdb), "no FSDB files exited"

        "AW Channel"
        tmpfile = "aw.tmp"
        exp = "%s==1 & %s==1"%(self.axi_signal_d["awvalid"], self.axi_signal_d["awready"])
        cmd = 'fsdbreport %s -exp \"%s\" -s \"%s\" -w 32 -o %s'%(self.args.fsdb, exp, self.axi_signal_d["awaddr"], tmpfile)
        os.system(cmd)
        assert os.path.isfile(tmpfile), "No AW tmp get"

        "W Channel"
        tmpfile = "w.tmp"
        exp = "%s==1 & %s==1"%(self.axi_signal_d["wvalid"], self.axi_signal_d["wready"])
        cmd = 'fsdbreport %s -exp \"%s\" -s \"%s\" -w 32 -o %s'%(self.args.fsdb, exp, self.axi_signal_d["wdata"], tmpfile)
        os.system(cmd)
        assert os.path.isfile(tmpfile), "No W tmp get"

        "B Channel"
        tmpfile = "b.tmp"
        exp = "%s==1 & %s==1"%(self.axi_signal_d["bvalid"], self.axi_signal_d["bready"])
        cmd = 'fsdbreport %s -exp \"%s\" -s \"%s\" -w 32 -o %s'%(self.args.fsdb, exp, self.axi_signal_d["bresp"], tmpfile)
        os.system(cmd)
        assert os.path.isfile(tmpfile), "No B tmp get"

        "AR Channel"
        tmpfile = "ar.tmp"
        exp = "%s==1 & %s==1"%(self.axi_signal_d["arvalid"], self.axi_signal_d["arready"])
        cmd = 'fsdbreport %s -exp \"%s\" -s \"%s\" -w 32 -o %s'%(self.args.fsdb, exp, self.axi_signal_d["araddr"], tmpfile)
        os.system(cmd)
        assert os.path.isfile(tmpfile), "No AR tmp get"

        "R Channel"
        tmpfile = "r.tmp"
        exp = "%s==1 & %s==1"%(self.axi_signal_d["rvalid"], self.axi_signal_d["rready"])
        cmd = 'fsdbreport %s -exp \"%s\" -s \"%s\" -w 32 -o %s'%(self.args.fsdb, exp, self.axi_signal_d["rdata"], tmpfile)
        os.system(cmd)
        assert os.path.isfile(tmpfile), "No R tmp get"

        "RRESP Channel"
        tmpfile = "rresp.tmp"
        exp = "%s==1 & %s==1"%(self.axi_signal_d["rvalid"], self.axi_signal_d["rready"])
        cmd = 'fsdbreport %s -exp \"%s\" -s \"%s\" -w 32 -o %s'%(self.args.fsdb, exp, self.axi_signal_d["rresp"], tmpfile)
        os.system(cmd)
        assert os.path.isfile(tmpfile), "No RRESP tmp get"

    def MergeTracer(self):
        trace_log=''
        with open("aw.tmp") as awf:
            aw_lines_t = awf.readlines()
            aw_lines = aw_lines_t[2:]
        with open("ar.tmp") as arf:
            ar_lines_t = arf.readlines()
            ar_lines = ar_lines_t[2:]
        with open("w.tmp") as wf:
            w_lines_t = wf.readlines()
            w_lines = w_lines_t[2:]
        with open("r.tmp") as rf:
            r_lines_t = rf.readlines()
            r_lines = r_lines_t[2:]
        with open("b.tmp") as bf:
            b_lines_t = bf.readlines()
            b_lines = b_lines_t[2:]
        with open("rresp.tmp") as rrespf:
            rresp_lines_t = rrespf.readlines()
            rresp_lines = rresp_lines_t[2:]

        "sort aw ar by time"
        trace_sort = []
        aw_ptr = 0
        ar_ptr = 0

        #while(aw_ptr < len(aw_lines)):
        for aw_ptr in range(0, len(aw_lines)-1):
            aws = " ".join(aw_lines[aw_ptr].split()).split(" ")
            
            while(ar_ptr < (len(ar_lines)-1)):
                ars = ar_lines[ar_ptr].split[" "]
                ars = " ".join(ar_lines[ar_ptr].split()).split(" ")
                
                if int(aws[0]) > int(ars[0]): 
                    trace_sort.append(["RREG", ars[0], ars[1]])
                    ar_ptr += 1
                else:
                    break
            trace_sort.append(["WREG", aws[0], aws[1]])
        
        if(ar_ptr < (len(ar_lines)-1)):
            for i in range(1, len(ar_lines)-1):
                ars = " ".join(ar_lines[i].split()).split(" ")
                trace_sort.append(["RREG", ars[0], ars[1]])
        assert len(trace_sort), "No Trans in Sort"

        w_ptr = 0
        r_ptr = 0
        for t in trace_sort:
            if t[0] == "WREG": 
               addr = hex(int(t[2], 2))
               if(len(w_lines)>(w_ptr+1)):
                   data = hex(int(" ".join(w_lines[w_ptr].split()).split(" ")[1], 2))
               else:
                   data = None
               if(len(b_lines)>(w_ptr+1)):
                   resp = hex(int(" ".join(b_lines[w_ptr].split()).split(" ")[1], 2))
               else:
                   resp = None
               trace_log ="%sTime: %s WREG : Addr %s : Data : %s : RESP : %s\n"%(\
                      trace_log,
                      t[1],
                      addr,
                      data,
                      resp
                   )
               w_ptr+=1
            elif t[0] == "RREG":
               addr = hex(int(t[2], 2))
               if(len(r_lines)>(r_ptr+1)):
                   data = hex(int(" ".join(r_lines[r_ptr].split()).split(" ")[1], 2))
               else:
                   data = None
               if(len(rresp_lines)>(r_ptr+1)):
                   resp = hex(int(" ".join(rresp_lines[r_ptr].split()).split(" ")[1], 2))
               else:
                   resp = None
               trace_log ="%sTime: %s RREG : Addr %s : Data : %s : RESP : %s\n"%(\
                      trace_log,
                      t[1],
                      addr,
                      data,
                      resp
                   )
               r_ptr+=1
        with open(self.args.outfile, "w") as out:
            out.write(trace_log)

    def Run(self):
        self.GetSignalPath()
        self.GetSignalTempFile()
        self.MergeTracer()

if __name__ == "__main__":
  try:
    tracer=AXI_CFG_TRACER()
    tracer.Run()
    os._exit(0)
  except KeyboardInterrupt:
      tracer.logger.info("Exit the FSDB Tracer")

  os._exit(0)
    
        
